package com.aqie.rabbit.service.Impl;

import com.aqie.rabbit.access.UserContext;
import com.aqie.rabbit.bean.api.account.LoginModel;
import com.aqie.rabbit.bean.api.account.RegisterModel;
import com.aqie.rabbit.bean.api.base.CodeMsg;
import com.aqie.rabbit.bean.db.User;
import com.aqie.rabbit.bean.db.UserFollow;
import com.aqie.rabbit.exception.GlobalException;
import com.aqie.rabbit.repositories.UserFollowRepository;
import com.aqie.rabbit.repositories.UserRepository;
import com.aqie.rabbit.service.IAccountService;
import com.aqie.rabbit.service.IPushService;
import com.aqie.rabbit.service.IUserFollowService;
import com.aqie.rabbit.service.IUserService;
import com.aqie.rabbit.utils.EncryptUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.dao.DataAccessException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Service
public class UserServiceImpl implements IUserService, IAccountService, IUserFollowService {

    @Autowired
    private UserRepository userRepository;

    @Autowired
    private UserFollowRepository userFollowRepository;

    @Autowired
    private IPushService pushService;

    @Override
    public User findById(String id) {
        return userRepository.findById(id).orElse(null);
    }

    @Override
    public User getFollowing(String id) {
        return userRepository.getFollowing(id).orElse(null);
    }

    @Override
    public User getFollower(String id) {
        return userRepository.getFollower(id).orElse(null);
    }

    @Override
    public int getFollowingNum(String id) {
        return userRepository.getFollowingNum(id).orElse(0);
    }

    @Override
    public User findByPhone(String phone) {
        return userRepository.findByPhone(phone).orElse(null);
    }

    @Override
    public User findByName(String name) {
        return userRepository.findByName(name).orElse(null);
    }

    @Override
    public List<User> findUserListByPushId(User user, String pushId) {
        return userRepository.findUserListByPushId(user.getId(),pushId);
    }

    @Override
    public User findByToken(String token) {
        return userRepository.findByToken(token).orElse(null);
    }

    /**
     * 注意更新用户对象(不允许更新用户名,)
     * 1. 提前判断
     * 2, 捕获异常
     * @param user
     * @return
     */
    @Override
    @Transactional
    public User update(User user) throws DataAccessException {
        UserContext.removeUser();
        UserContext.setUser(user);
        return userRepository.save(user);
    }

    /**
     * 查询 当前登录用户
     * 获取登录用户的关注人列表
     * @return
     */
    @Override
    public List<User> contact(String id) {
        User user = userRepository.contact(id).orElse(null);
        // User user = userRepository.contact("f1f502d4-1b75-4525-aac7-5eb30d03c0a3").orElse(null);
        if (user == null){
            return null;
        }

        Set<UserFollow> follows = user.getFollowing();

        // 用户关注列表
        return follows.stream()
                .map(UserFollow::getTarget)
                .collect(Collectors.toList());
    }

    @Override
    @Transactional
    public User follow(final User origin,final User target, final String alias){
        UserFollow originFollow = new UserFollow();
        originFollow.setOrigin(origin);
        originFollow.setTarget(target);
        originFollow.setAlias(alias);
        // todo 数据库可能报错
        userFollowRepository.save(originFollow);
        return target;
    }

    /**
     * 获取登录用户信息
     * 带扩展 从缓存/redis数据库获取
     * todo
     * @return
     */
    @Override
    public User getUser() {
        User user = UserContext.getUser();
        if (user == null){
            throw new GlobalException(CodeMsg.TOKEN_INVALID_ERROR);
        }
        return user;
    }

    @Override
    public List<User> search(String name,String id) {
        final String searchName = "%" + name + "%";
        return userRepository.findByNameComplete(searchName,id).orElse(null);
    }

    @Override
    @Transactional
    public User register(RegisterModel model) {
        User user = new User();
        user.setPhone(model.getAccount());
        user.setName(model.getName());
        String password = EncryptUtil.encodePassword(model.getPassword());
        user.setPassword(password);
        user.setToken(EncryptUtil.generateToken());

        return userRepository.save(user);
    }

    @Override
    @Transactional
    public User login(LoginModel model) {
        String password = EncryptUtil.encodePassword(model.getPassword().trim());
        String account = model.getAccount().trim();
        User user =  userRepository.findByPasswordAndPhone(password,account).orElse(null);
        if (user != null){
            user.setToken(EncryptUtil.generateToken());
            return userRepository.save(user);
        }
        return null;
    }

    @Override
    @Transactional
    public User bindPushId(User user, String pushId) {
        // 如果除本账户外，其他账户绑定该设备id 本地session置空该用户的pushId
        List<User> userList = findUserListByPushId(user,pushId);
        if (userList.size() > 0){
            // todo 更新本地session 中用户推送id 为null
        }
        // 当前账户需要绑定设备pushId 和 持有的设备pushId一致
        if (pushId.equalsIgnoreCase(user.getPushId())){
            return user;
        }else{
            /**
             * 当前账户之前的pushId，和需要绑定的不同
             * 单点登录，让之前的设备退出账户
             * 给之前的设备对应pushId推送一条退出消息
             * 更新账户的设备id至最新
             */
            // 推送一个退出消息
            pushService.pushLogout(user, user.getPushId());
            user.setPushId(pushId);
            return userRepository.save(user);
        }

    }


    /**
     * 不仅查询出UserFollow表一条数据,还会查出 关注者及被关注者两个对象
     * @param originId
     * @param targetId
     * @return
     */
    @Override
    public UserFollow getUserFollow(final String originId,final String targetId) {
        return userFollowRepository.findByOriginIdAndTargetId(originId,targetId);
    }



}
